package models;


import java.util.ArrayList;
import java.util.List;

import com.google.appengine.api.NamespaceManager;

import play.Logger;
import play.modules.m4fcity.M4FCityApiService;
import play.modules.m4fcity.M4FCityProfile;
import play.modules.m4fcity.OrganizationCity;
import play.modules.market.MarketProfile;
import play.mvc.Scope.Session;
import siena.Filter;
import siena.Id;
import siena.Model;
import siena.Query;
import siena.embed.Embedded;
import siena.embed.Embedded.Mode;
import utils.constants.SessionConstants;

public class User extends Model {
	@Id private Long id;
	
	@Embedded(mode=Mode.NATIVE)
	private Profile profile;
	
	private List<String> roles;
	
	private Boolean access;
	
	@Filter("owner")
    public Query<Focus> focuses;
    
	@Filter("author")
    public Query<InformationUnit> informations;
	
	@Filter("author")
    public Query<IdeaUnit> ideas;
    

	
	public User() {
		this.access = false;
		this.roles = new ArrayList<String>();
		this.profile = new Profile();	
	}
	 
	public User(Profile profile) {
		this();
		this.profile = profile;
		this.access = profile.isManager();
	}
	
	public static Query<User> all() {
		return Model.all(User.class);
	}
	
	public static User findById(Long id) {
		return all().filter("id", id).get();
	}
	
	public static User findById(String id) {
		try {
			return User.findById(Long.parseLong(id));
		} catch(NumberFormatException e) {
			Logger.error("Fail converting the user id from String to Long: ", e.getMessage());
			return null;
		}
	}
	
	public static User findByProfileEmail(String typeProfile, String email) {
		return all().filter("profile.type", typeProfile).filter("profile.email", email).get();
	}
	
	public static List<User> findByEmail(String email) {
		return all().filter("profile.email", email).fetch();
	}
	
	public static User findByProfileId(String profileId) {
		Logger.info("User.findByProfileId: %s", profileId);
		return all().filter("profile.id", profileId).get();
	}
	
	public static List<User> findByDomain(String domain) {
		return all().filter("profile.domain", domain).fetch(); // TODO fix it!!
		//return all().fetch();
	}
	
	// To use in m4fcity-api module
	public static void findForM4FCityOAuth(M4FCityProfile profile){
		User user = findByProfileId(Profile.M4FCITY_PREFIX+profile.getId());
		if(user == null) {
			Logger.info("Creating new user from m4fcity: ", user);
			user = new User(new Profile(profile));
		} else {
			Logger.info("Found user from m4fcity: %s", user.getProfile().getId());
			user.setProfile(new Profile(profile));
		}
		try {
			// TODO set the namespace to the domain
			//String domain = Session.current().get(SessionConstants.DOMAIN);
			//NamespaceManager.set(domain);
			
			// Save the user
			user.save();
			
		} catch(Exception e) {
			e.printStackTrace();
		}
		
		OrganizationCity orgCity = M4FCityApiService.gerOrganization(user.getProfile().getAccessToken());
		// *** INFO For Secure.Security ***
        Session.current().put(SessionConstants.USER, user.getId());
        Session.current().put(SessionConstants.DOMAIN, orgCity.getDomain());
    }
	
	public static void findForMarketOAuth(MarketProfile profile) {
		//User user = findByProfileId(Profile.MARKET_PREFIX+profile.getId());
		User user = findByProfileEmail(Profile.MARKET_PREFIX, profile.getUserName()+"@"+profile.getDomain());
		
		if(user == null) {
			Logger.info("Creating new user from market: ", profile.getId());
			user = new User(new Profile(profile));
		} else {
			Logger.info("Found user from market: %s", user.getProfile().getId());
			user.setProfile(new Profile(profile));
			if(!user.hasAccess()) user.setAccess(user.profile.isManager()); // Update always access flag with manager flag from profile.
		}
		try {	
	        //String domain = Session.current().get(SessionConstants.DOMAIN);
			//NamespaceManager.set(domain);
			
			// Save the user
			user.save();
		} catch(Exception e) {
			e.printStackTrace();
		}
		
		// TODO set the namespace to the domain
		// *** INFO For Secure.Security ***
        Session.current().put(SessionConstants.USER, user.getId());
        Session.current().put(SessionConstants.DOMAIN, user.getProfile().getDomain());
	}
		
	// GETTERS AND SETTERS
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}
	
	public Profile getProfile() {
		return profile;
	}

	public void setProfile(Profile profile) {
		this.profile = profile;
	}

	public List<String> getRoles() {
		return roles;
	}

	public void setRoles(List<String> roles) {
		this.roles = roles;
	}
	
	public Boolean hasAccess() {
		return this.access;
	}
	
	public void setAccess(Boolean access) {
		this.access = access;
	}

	@Override
	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append(profile != null && profile.getEmail() != null ?
				profile.getEmail() : "");
		return sb.toString();
	}
	
	@Override
	public boolean equals(Object object) {
		if(object instanceof User) {
			User user = (User) object ;
			if(this.id != null) {
				return this.id.equals(user.getId());
			}
		}
		return false;
	}
}
